iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 6
0
自我挑戰組

從零開始的Flutter世界系列 第 6

Day06 Dart 語言介紹(四) static、Exception

  • 分享至 

  • xImage
  •  

類別類的屬性 static

  • 與 excel 絕對位置的觀念一樣

  • 所有的物件都共用同一屬性

  • Class 的屬性可分為:

    1. 物件類:

      • 每個物件都有自己的屬性內容

      • 透過實體化出來的物件來呼叫物件類的屬性

      • 案例介紹:

        本金都固定,比較各家銀行儲蓄方案

        class Bank {
          int _pv;
          double _rate;
          int _n;
          int _fv;
        
          Bank(this._pv, this._rate, this._n) {
            _fv = (_pv * (1 + _rate * _n)).toInt();
          }
        
          void setPv(int pv) {
            this._pv = pv;
          }
        
          void show() {
            print("本金 = $_pv, 利率 = $_rate, 期數 = $_n, 單利本利和 = $_fv");
          }
        }
        
        main() {
          /*
          Bank m1 = new Bank(100000, 0.01, 6);
        
          物件類屬性:
          m1.pv
          m1.rate
          m1.n
          m1.fv
          */
          Bank yuantaBank = new Bank(100000, 0.01, 3);
          Bank taiwanBank = new Bank(100000, 0.012, 5);
          Bank esunBank = new Bank(100000, 0.015, 10);
        
          yuantaBank.show(); //印出 本金 = 100000, 利率 = 0.01, 期數 = 3, 單利本利和 = 103000
          taiwanBank.show(); //印出 本金 = 100000, 利率 = 0.012, 期數 = 5, 單利本利和 = 106000
          esunBank.show(); //印出 本金 = 100000, 利率 = 0.015, 期數 = 10, 單利本利和 = 114999
        
          /*
          若之後想修改本金看看新結果,每一個物件還需要各自修改
          例如:
          yuantaBank.setPv(200000);
          taiwanBank.setPv(200000);
          esunBank.setPv(200000);
          所有物件都使用同一個屬性內容,故應宣告為類別類屬性
          */
        }
        
    2. 類別類:

      • 因為每個物件都呼叫同一個屬性內容,故稱類別類的屬性,不需透過物件,可以直接透過類別呼叫

        class Bank {
          static int pv; //類別類屬性
          double _rate;
          int _n;
          int _fv;
        
          Bank(this._rate, this._n) {
            _fv = (pv * (1 + _rate * _n)).toInt();
          }
        
          void show() {
            print("本金 = $pv, 利率 = $_rate, 期數 = $_n, 單利本利和 = $_fv");
          }
        }
        
        main() {
          //呼叫類別類,直接對 類別類的屬性做傅值
          Bank.pv = 100000;
        
          Bank yuantaBank = new Bank(0.01, 3);
          Bank taiwanBank = new Bank(0.012, 5);
          Bank esunBank = new Bank(0.015, 10);
        
          yuantaBank.show(); //印出 本金 = 100000, 利率 = 0.01, 期數 = 3, 單利本利和 = 103000
          taiwanBank.show(); //印出 本金 = 100000, 利率 = 0.012, 期數 = 5, 單利本利和 = 106000
          esunBank.show(); //印出 本金 = 100000, 利率 = 0.015, 期數 = 10, 單利本利和 = 114999
        
          /*
          若之後想修改本金看看新結果,直接對類別類共同屬性pv 做修改即可
          例如:
          Bank.pv = 200000;
          */
        }
        
  • 使用對象:

    1. field區屬性,即靜態變數,又稱類別類變數

      常用在對類別的共用狀態屬性以及常數上,在使用之前不會初始化

      class Queue {
        static const initialCapacity = 16;
        // ···
      }
      
      void main() {
        print(Queue.initialCapacity); //印出 16
      }
      
    2. 方法(函數),即靜態方法(函數),又稱類別類方法

      靜態方法不在instance 例項是執行,所以無法使用this (物件本身的變數,即class的field區)

      import 'dart:math';
      
      class Point {
        num x, y;
        Point(this.x, this.y);
      
        static num distanceBetween(Point a, Point b) {
          var dx = a.x - b.x;
          var dy = a.y - b.y;
          return sqrt(dx * dx + dy * dy);
        }
      }
      
      void main() {
        var a = Point(2, 2);
        var b = Point(4, 4);
        var distance = Point.distanceBetween(a, b);
      
        print(distance); //印出 2.8284271247461903
      }
      
  • 補充:

    1. 類別的 Constant constructors(常量建構式)

      如果要設計一個類別讓它生成的物件狀態永遠不會改變,可以把這些物件定義為編譯時常量,要實現這個功能,則需要定義一個const建構式, 並且宣告所有類的屬性皆為final

      class ImmutablePoint {
        static final ImmutablePoint origin =
            const ImmutablePoint(0, 0);
      
        final double x, y;
      
        const ImmutablePoint(this.x, this.y);
      }
      
      void main() {
      
        ImmutablePoint a = ImmutablePoint(3,4);
        // a.x = 5;   會報錯,ImmutablePoint 生出來的物件a,它的變數為常數,不能改變
        print("x = ${a.x}, y = ${a.y}"); //印出 x = 3, y = 4
      }
      
    2. 類別的 Factory constructors(工廠方法建構式)

      當建構式不需要每次都創建新的實例時,可以使用factory來定義這個建構函式。例如,一個工廠建構函式可能從快取中獲取一個例項並返回,或者返回一個子類別的例項 (子類別後面會再介紹)

      Factory constructors 一樣不能使用this

      class Logger {
        final String name;
        bool mute = false;
      
        static final Map<String, Logger> _cache = <String, Logger>{};
      
        factory Logger(String name) {
          if (_cache.containsKey(name)) {
            return _cache[name];
          } else {
            final logger = Logger._internal(name);
            _cache[name] = logger;
            return logger;
          }
        }
      
        Logger._internal(this.name);
      
        void log(String msg) {
          if (!mute) print(msg);
        }
      }
      
      void main() {
        var logger = new Logger('UI');
        logger.log('Button clicked'); //印出 Button clicked
      }
      

Exception 例外異常處理

程式碼中可以有異常和捕獲異常,Exceptions 表示在執行程式期間出現的問題,發生一些未知的錯誤情況,若沒對這些Exceptions 作處理,會導致我們程式結束執行。和java 不同的是,所有的Dart 異常是非檢查異常 unchecked exceptions,方法不會聲明它們可能引發的異常,並且不需要捕獲任何異常。

Dart提供了ExceptionError型別,以及一些子型別。還可以自己定義異常型別。但是,Dart程式碼可以丟擲任何非null物件為異常,不僅限於ExceptionError物件。 ( 不過還是建議使用ExceptionError型別 )

Throw

拋出異常:

throw new FormatException('Expected at least 1 section');

還可以拋出任意物件:

throw 'Out of llamas!';
Catch

捕獲異常:

將可能發生錯誤的程式碼放在 try區塊內,用on/catch處理發生異常時要做的動作

main() {
  try {
    testAge(-2);
  } catch (e) {
    print('Age cannot be negative');
  }
}

void testAge(int age) {
  if (age < 0) {
    throw new FormatException();
  }
}

要處理可能拋出多種型態異常的程式碼,可以指定多個catch語句。每個語句分別對應一個異常型別,如果catch 語句沒有指定異常型別,則該語句可以處理任何異常型別:

try {
  breedMoreLlamas();
} on OutOfLlamasException {
  // A specific exception
  buyMoreLlamas();
} on Exception catch (e) {
  // Anything else that is an exception
  print('Unknown exception: $e');
} catch (e) {
  // No specified type, handles all
  print('Something really unknown: $e');
}

如上述程式碼所示,可以使用on或者catch來宣告捕獲語句,或兩者同時使用。使用on來指定異常型別,使用catch來捕獲異常物件。

函式catch()可以帶有一個或者兩個引數,第一個引數為丟擲的異常物件,第二個為 StackTrace object。

try {
  // ···
} on Exception catch (e) {
  print('Exception details:\n $e');
} catch (e, s) {
  print('Exception details:\n $e');
  print('Stack trace:\n $s');
}

要部分處理異常,同時允許異常傳遞,可以使用rethrow

void misbehave() {
  try {
    dynamic foo = true;
    print(foo++); // Runtime error
  } catch (e) {
    print('misbehave() partially handled ${e.runtimeType}.');
    rethrow; // Allow callers to see the exception.
  }
}

void main() {
  try {
    misbehave();
  } catch (e) {
    print('main() finished handling ${e.runtimeType}.');
  }
}
Finally

無論是否拋出異常,都要確保某些程式碼會執行,可以使用finally語句來實現。如果沒有匹配的catch語句來捕獲異常,則該異常會在執行finally語句後被拋出

try {
  breedMoreLlamas();
} finally {
  // Always clean up, even if an exception is thrown.
  cleanLlamaStalls();
}

定義的finally語句在任何匹配的catch語句之後執行:

try {
  breedMoreLlamas();
} catch(e) {
  print('Error: $e');  // 先處理異常
} finally {
  cleanLlamaStalls();  // 再執行 finally語句
}

現在我們對於使用一個類別的操作上有比較熟悉了,包括如何設計類別、使用它的變數以及方法等等,接下來我們將介紹,類別的繼承、多型的內容,Dart 的語言介紹系列還會有幾天,為了讓以後我們能夠更順利開發專案,這幾天可能會辛苦一點


上一篇
Day05 Dart 語言介紹(三) 類別、函式
下一篇
Day07 Dart 語言介紹(五) 繼承、多型
系列文
從零開始的Flutter世界30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言